{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# Finding adversarial examples, in depth\n",
    "\n",
    "In the quickstart, we used the default parameters for `find_adversarial_example`. Using the same example from the quickstart, we explore how to get more out of the function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: Method definition midpoints(Base.Range{T} where T) in module Base at deprecated.jl:56 overwritten in module StatsBase at /home/vtjeng/.julia/v0.6/StatsBase/src/hist.jl:535.\n",
      "WARNING: Method definition midpoints(AbstractArray{T, 1} where T) in module Base at deprecated.jl:56 overwritten in module StatsBase at /home/vtjeng/.julia/v0.6/StatsBase/src/hist.jl:533.\n"
     ]
    }
   ],
   "source": [
    "using MIPVerify\n",
    "using Gurobi\n",
    "using JuMP\n",
    "using Images\n",
    "\n",
    "mnist = MIPVerify.read_datasets(\"MNIST\")\n",
    "n1params = MIPVerify.get_example_network_params(\"MNIST.n1\")\n",
    "sample_image = MIPVerify.get_image(mnist.train.images, 1);\n",
    "\n",
    "function print_summary(d::Dict)\n",
    "    # Helper function to print out output\n",
    "    obj_val = getobjectivevalue(d[:Model])\n",
    "    solve_time = getsolvetime(d[:Model])\n",
    "    println(\"Objective Value: $(@sprintf(\"%.6f\", obj_val)), Solve Time: $(@sprintf(\"%.2f\", solve_time))\")\n",
    "end\n",
    "\n",
    "function view_diff(diff::Array{<:Real, 2})\n",
    "    n = 1001\n",
    "    colormap(\"RdBu\", n)[ceil.(Int, (diff+1)/2*n)]\n",
    "end;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## `find_adversarial_example`\n",
    "\n",
    "`find_adversarial_example` takes four positional arguments\n",
    "\n",
    "```\n",
    "find_adversarial_example(nnparams, input, target_selection, main_solver)\n",
    "```\n",
    "\n",
    "It also takes named arguments, each with the default value specified.\n",
    "\n",
    "```\n",
    "norm_order = 1\n",
    "tolerance = 0\n",
    "rebuild = false\n",
    "invert_target_selection = false\n",
    "pp = MIPVerify.AdditivePerturbationParameters()\n",
    "model_build_solver: same as main solver, but with output suppressed and a time limit of 20s per solve.\n",
    "```\n",
    "\n",
    "We explore what each of these options allow us to do."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# Basic Options"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Specifying target categories for the adversarial example\n",
    "\n",
    "`target_selection` and `invert_target_selection` control what the category we want the adversarial example to be classified in.\n",
    "\n",
    "**Specification**: `target_selection` accepts either a single integer or a list of integers.\n",
    "\n",
    "For example, if I wanted the original image (which is the digit 7) to be classified as the digit 0 or 8, I could run two separate solves with `target_selection=1` and `target_selection=9` (Julia is 1-indexed), finding closest adversarial examples at distance `15.0926` and `9.75700` ..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Rebuilding model from scratch. This may take some time as we determine upper and lower bounds for the input to each non-linear unit. The model built will be cached and re-used for future solves, unless you explicitly set rebuild=false.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [1]\n",
      "\u001b[39mObjective Value: 15.092612, Solve Time: 55.89\n"
     ]
    }
   ],
   "source": [
    "d = MIPVerify.find_adversarial_example(n1params, sample_image, 1, GurobiSolver(OutputFlag=0))\n",
    "# OutputFlag=0 prevents any output from being printed out\n",
    "print_summary(d)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [9]\n",
      "\u001b[39mObjective Value: 9.756997, Solve Time: 10.64\n"
     ]
    }
   ],
   "source": [
    "d = MIPVerify.find_adversarial_example(n1params, sample_image, 9, GurobiSolver(OutputFlag=0));\n",
    "print_summary(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "Or I can can pass the targets as  `target_selection = [1, 9]`, where the same optimal value of `9.75700` is found.\n",
    "\n",
    "Solve times for multiple target labels are typically on par with or faster than the aggregate solve times when solving with each target label in sequence."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [1, 9]\n",
      "\u001b[39mObjective Value: 9.756997, Solve Time: 41.17\n"
     ]
    }
   ],
   "source": [
    "d = MIPVerify.find_adversarial_example(n1params, sample_image, [1, 9], GurobiSolver(OutputFlag=0));\n",
    "print_summary(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "A common use case is to have the adversarial example being in any category but the original:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [1, 2, 3, 4, 5, 6, 7, 9, 10]\n",
      "\u001b[39mObjective Value: 3.171856, Solve Time: 31.02\n"
     ]
    }
   ],
   "source": [
    "d = MIPVerify.find_adversarial_example(n1params, sample_image, [1, 2, 3, 4, 5, 6, 7, 9, 10], GurobiSolver(OutputFlag=0))\n",
    "print_summary(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "Rather than typing the full list of other categories, we can set `target_selection = 8`, and `invert_target_selection = true`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [1, 2, 3, 4, 5, 6, 7, 9, 10]\n",
      "\u001b[39mObjective Value: 3.171856, Solve Time: 27.80\n"
     ]
    }
   ],
   "source": [
    "d = MIPVerify.find_adversarial_example(n1params, sample_image, 8, GurobiSolver(OutputFlag=0), \n",
    "    invert_target_selection=true)\n",
    "print_summary(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## More precise control over activations in output layer\n",
    "### Default Behavior\n",
    "The default option for `tolerance` is 0. This means that the activations in the softmax layer will take its maximum value for the target label (or at least one of them if more than one is specified), but that this maximum may not be unique.\n",
    "\n",
    "In the example below, notice how the activations `y[8]` and `y[10]` (corresponding to labels 7 and 9) are equal, at 3.49171."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [10]\n",
      "\u001b[39mObjective Value: 3.171856, Solve Time: 4.42\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "10-element Array{Float64,1}:\n",
       " 0.388105\n",
       " 0.515855\n",
       " 1.25875 \n",
       " 0.296821\n",
       " 0.410448\n",
       " 0.556019\n",
       " 0.444605\n",
       " 3.49171 \n",
       " 0.412949\n",
       " 3.49171 "
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d = MIPVerify.find_adversarial_example(n1params, sample_image, 10, GurobiSolver(OutputFlag=0))\n",
    "print_summary(d)\n",
    "perturbed_sample_image = getvalue(d[:PerturbedInput])\n",
    "y = perturbed_sample_image |> n1params"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "### Ensuring difference in activation between target labels and non-target labels\n",
    "\n",
    "If we want to ensure that the maximum is unique, we can add a small tolerance. This is the minimum difference between the activation of the target label (or the maximum activation of any of the target labels) and any non-target label. In the example below, with a tolerance of 0.001, notice how `y[8] = 3.49243 = 0.00100 + 3.49143 = tolerance + y[10]`.\n",
    "\n",
    "_This increases the objective value slightly (since the closest adversarial example with the required tolerance must be slightly further away.)_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [10]\n",
      "\u001b[39mObjective Value: 3.172870, Solve Time: 3.15\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "10-element Array{Float64,1}:\n",
       " 0.388176\n",
       " 0.515929\n",
       " 1.2587  \n",
       " 0.296866\n",
       " 0.410472\n",
       " 0.556048\n",
       " 0.444678\n",
       " 3.49143 \n",
       " 0.41283 \n",
       " 3.49243 "
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d = MIPVerify.find_adversarial_example(n1params, sample_image, 10, GurobiSolver(OutputFlag=0), \n",
    "    tolerance = 0.001)\n",
    "print_summary(d)\n",
    "perturbed_sample_image = getvalue(d[:PerturbedInput])\n",
    "y = perturbed_sample_image |> n1params"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Restricting the Family of Perturbations\n",
    "\n",
    "### Additive Perturbations\n",
    "\n",
    "The standard threat model is to allow each pixel to be perturbed independently, which is what happens by default:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [10]\n",
      "\u001b[39m  3.426842 seconds (503.42 k allocations: 22.181 MiB, 0.49% gc time)\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHAAAABwCAAAAADji6uXAAAABGdBTUEAALGPC/xhBQAAAAJiS0dEAP+Hj8y/AAAAB3RJTUUH4gIWAR8lH3b75AAAAXxJREFUaN7t2c8rBGEcx/E9cHRRkpNSlJtyclg5cJKLpDhxdZNwcXBG/gNXcXMXV06SkgNRKEX5GYks72/tU9M0trGe+UGf12nbefZ577RPu8/MFgoiIiIiIiIpG8cYBjCDIhTMV3AUC7DHNxHey15RwjPs+W00QMFsg0uwyUpV2kIjFMwueA574T52QhZRjDCPUwSjsRePgt6DbRhEHWJ/8GjBIVx0CgpmE/yNIbjgNRRUUMF0gxNYgQs+oRMKZhf8xHfHmjCNy4APhDdU91Awu2CUXsziBHE2xctQMB/BVmwivDDOsFfWD3tDR3DHbWFFzdcDBdMLTuIYNsEjLmCb3BE0Izx+Fzb2Ae1wz1f6IlEw2eA6bIINdKPS2A5cwcZXvYlS0HuwHnOIMza4EV6FgvkI/oTdOLLYLbqg4N8KHuANFlxD4menoHf242yxO6SyQhX0yjZU9ueKbZyGkfjZKehVLexi5gV2Yyjxs1PQuxrYhWcfEo8pKP/bFw+rnwoHRW1DAAAAAElFTkSuQmCC",
      "text/plain": [
       "28×28 Array{Gray{Float64},2}:\n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)  …  Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)  …  Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)  …  Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " ⋮                                       ⋱                         \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.250287)\n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)  …  Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)  …  Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     "
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d = @time MIPVerify.find_adversarial_example(n1params, sample_image, 10, GurobiSolver(OutputFlag=0));\n",
    "perturbed_sample_image = getvalue(d[:PerturbedInput])\n",
    "colorview(Gray, perturbed_sample_image[1, :, :, 1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "### Blurring Perturbations\n",
    "\n",
    "We can restrict the perturbations to a blur with a 5x5 kernel instead. (We are still minimizing over the norm of the perturbation.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [10]\n",
      "\u001b[39m  1.312196 seconds (444.23 k allocations: 22.444 MiB, 0.69% gc time)\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHAAAABwCAAAAADji6uXAAAABGdBTUEAALGPC/xhBQAAAAJiS0dEAP+Hj8y/AAAAB3RJTUUH4gIWAR8mhn+qXgAAAj5JREFUaN7t2l1ojXEcwPHJ2wVS8paXlkhmFBckF6LEvCRFpBaasgurCbnggly5oEiiLCu5caGUkshWbCFRW+1qcuNCSSmxhNa+33pWp3XiLOd/nhO/z+XOs77n1P95nt//OaemJoQQQgjhPzQf8zALCzENEayu4FzUYVMRB9CCZrTiMHbA19ZgAiKYb3ADTuIqbhbRhW504A0eoh1XcAhrMRERzCe4CPfQh4/4MIJ/78o8g+Gn6MU73MBwtKTFE8GyB4/gETpxG+0FLsHF1DrCWbiY/L9+tMGobz6ClQ/uwzHsxmYUXrRXYkYRy7EXnvgv4OI6j52IYOWDU+CANB5/PLjAZBzEYwzCcCMiWPng39iFHhj8gv2YighWZ9AhyU3MxozDsTffbzD4FUexHRGsruB0LEUTLqMt8xxvMZj5gftwqI5gdQQnYQtcCNfxCi6QT/CG+xkvYdiT3qhvYAUimH+wHifwAIbc5LipcSNzF7fgMOzwdQ2+btBNkQ+OIphv0IHqHN5nnuACTsML9jY0YA5m4yJcND/h5mccIphv0MHIjakPENyM7sES1MKLQeGxDsNuXH/BG7DHjioWwSTB9XCBbMVM/O7YxfCB0fCFewEimH/QB3TLUMqxZ+BJ7wDlgDXaTW0E0wRLtRqv4YLxQe0qJItFMAkHKW+6AziFpAsmgmXn8OTD9e9w+PXL6KSfLoJlNQYOS35xeQc+cE/66SJYdmPhDwiOYx2SxiKYhIvGH4l48iePRTD824YAwC6Jugv+jkMAAAAASUVORK5CYII=",
      "text/plain": [
       "28×28 Array{Gray{Float64},2}:\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)  …  Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)     Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)     Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)     Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)     Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)  …  Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(0.0)      Gray{Float64}(-0.0)\n",
       " Gray{Float64}(0.0)   Gray{Float64}(0.0)      Gray{Float64}(-0.0)\n",
       " Gray{Float64}(0.0)   Gray{Float64}(0.0)      Gray{Float64}(-0.0)\n",
       " Gray{Float64}(0.0)   Gray{Float64}(0.0)      Gray{Float64}(-0.0)\n",
       " Gray{Float64}(0.0)   Gray{Float64}(0.0)   …  Gray{Float64}(-0.0)\n",
       " Gray{Float64}(0.0)   Gray{Float64}(0.0)      Gray{Float64}(-0.0)\n",
       " Gray{Float64}(0.0)   Gray{Float64}(0.0)      Gray{Float64}(-0.0)\n",
       " ⋮                                         ⋱                     \n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)     Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)     Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)     Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)     Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)  …  Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)     Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)     Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)     Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)     Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)  …  Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)     Gray{Float64}(-0.0)\n",
       " Gray{Float64}(-0.0)  Gray{Float64}(-0.0)     Gray{Float64}(-0.0)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d = @time MIPVerify.find_adversarial_example(n1params, sample_image, 10, GurobiSolver(OutputFlag=0),\n",
    "    pp = MIPVerify.BlurPerturbationParameters((5, 5)));\n",
    "perturbed_sample_image = getvalue(d[:PerturbedInput])\n",
    "colorview(Gray, perturbed_sample_image[1, :, :, 1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHAAAABwCAMAAADxPgR5AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAB41BMVEX5+Pna7/vf8fzU7Pvj8/zc8PzP6vqy2/aZzPGKwu6Qxu+Hwe2Rx++q1vXA4vjt+P643veAu+tfot5WmdiUyfCSx/CFv+yg0PN7uOlVmNhipN++4fjT7Puh0fOt2PX/9fL/9PD/6OL/0MT/0sb/z8P/08j/5t/X7vturuX/4dn/ybv/yr3/sqL/rp7/n47+g3H7e2r/j33/rZ3/xrjY7vtwr+X+gnD9f23/kX//jHr/i3n/3NL/uar/hHL/opH/0cXN6fqDveyo1fT/5+D/8e3/mIf/x7qj0vOczvL/2M7s9/3l9P203Pax2vb/8Ozq9v2HwO2s2PXh8vzO6fqVyvFjpeBZnNqazfK63/d1tOe33vfp9v2v2faGwO13tOii0vPk9P3w+f7/7uj/0MX/7+r/6uPH5vmBvOuEvuyk0/Tm9f3/29H/uqv/saD/ppXV7fve8fzZ7/v/yLv/m4r/iXf/inj/hnT/1cv/2c7/wbP/9PHb8Pzv+f7/49v/zsH/kH78fWz/wbL/zsLo9v3/29LL6Pr/pJP/iHb/p5b/39b/7ejW7fv/u6zM6fr/6ePC4/i33ff/9vP/7Ob/1svy+v7/183d8fz/6OH/8u//5Nzx+f7/2M3/wrT/rp3/9fH/v7H///8FX6MaAAAAAWJLR0SgXtO+oAAAAAd0SU1FB+ICFgEfKGHHh1kAAAIWSURBVGje7dj3T9RgHMdxBAUUlaGAExAQFcGNuJClMlQQVEBAcO+Fm6WIigs3bsV/1fcnuUsu5KKcttcSv6+femmv7zZpm+d5YmKMMcYYY/5D0wJiEYfpsKC/gjMQj4QwEjETs5CE2ZgD7ZuLZFjQ22AKUpGGeWHMRzoykIkFWIhF0L7FiChqQUeDS7AUWchGzgTLkBuQh3wsRwFWYCUiilrQ8eAqFGI1ilAcYg3WYt0E67EBG7EJJVBUF2/B6Ac3oxRbsBXbQugCtoexA2XYiXJUoBJVsGD0g9XQC70Lfzw4hD4Iu7EH+l2DWlgw+sF/oY99HbRdDw229sKC/gzqhJrE7AvQyfejAdrfiANoggX9FWzGQRzCYbQEtKINoRd0BO2woD+CHejEUXShG8egEx/HCeijfxKnoP+cxhlY0PugBkVncQ7ncQEXoYnMJVyGBsMafF2BQvrfVVyDBb0N9kAvtRaJNOm8jhu4CQ2Ub+E27uAueqGHpg/9GIAFvQ0OQgsI93AfQ3iAYQQfjqCHeAQNpvQxeIyIYhZ0JTiCJ3gKTT5/d6wGUM+g7ed4AQt6H9RLPIrJHPsSOl6LgK/wV6v7FnQ8OFmv8QZv8Q6KuhazoCveYwxaUPoAVx8YCzruIz7hM7Q4/wWu3p0FHfUVGvR+w3doEOXq3VnQcRr0ahKqyc0PuBqzoCvG8RPBxXULTr2g8Y1ffOX4LmhiUq0AAAAASUVORK5CYII=",
      "text/plain": [
       "28×28 Array{RGB{Float64},2}:\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)  …  RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)  …  RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)  …  RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " ⋮                                         ⋱                                          \n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)  …  RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)  …  RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "diff = getvalue(d[:Perturbation])\n",
    "view_diff(diff[1, :, :, 1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Minimizing Over Different Norms\n",
    "### $l_1$\n",
    "By default, we minimize the $l_1$ norm of the perturbation. This generally encourages sparsity in the perturbations. \n",
    "\n",
    "In this case, the minimum $l_1$ norm perturbation required for the image to be classified as a `9` is `3.171856.`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [10]\n",
      "\u001b[39mObjective Value: 3.171856, Solve Time: 4.41\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHAAAABwCAAAAADji6uXAAAABGdBTUEAALGPC/xhBQAAAAJiS0dEAP+Hj8y/AAAAB3RJTUUH4gIWAR8tEa1z1gAAAXxJREFUaN7t2c8rBGEcx/E9cHRRkpNSlJtyclg5cJKLpDhxdZNwcXBG/gNXcXMXV06SkgNRKEX5GYks72/tU9M0trGe+UGf12nbefZ577RPu8/MFgoiIiIiIiIpG8cYBjCDIhTMV3AUC7DHNxHey15RwjPs+W00QMFsg0uwyUpV2kIjFMwueA574T52QhZRjDCPUwSjsRePgt6DbRhEHWJ/8GjBIVx0CgpmE/yNIbjgNRRUUMF0gxNYgQs+oRMKZhf8xHfHmjCNy4APhDdU91Awu2CUXsziBHE2xctQMB/BVmwivDDOsFfWD3tDR3DHbWFFzdcDBdMLTuIYNsEjLmCb3BE0Izx+Fzb2Ae1wz1f6IlEw2eA6bIINdKPS2A5cwcZXvYlS0HuwHnOIMza4EV6FgvkI/oTdOLLYLbqg4N8KHuANFlxD4menoHf242yxO6SyQhX0yjZU9ueKbZyGkfjZKehVLexi5gV2Yyjxs1PQuxrYhWcfEo8pKP/bFw+rnwoHRW1DAAAAAElFTkSuQmCC",
      "text/plain": [
       "28×28 Array{Gray{Float64},2}:\n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)  …  Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)  …  Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)  …  Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " ⋮                                       ⋱                         \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.250287)\n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)  …  Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)  …  Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     \n",
       " Gray{Float64}(0.0)  Gray{Float64}(0.0)     Gray{Float64}(0.0)     "
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d = MIPVerify.find_adversarial_example(n1params, sample_image, 10, GurobiSolver(OutputFlag=0));\n",
    "print_summary(d)\n",
    "perturbed_sample_image = getvalue(d[:PerturbedInput])\n",
    "colorview(Gray, perturbed_sample_image[1, :, :, 1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "We also show the difference between the perturbed image and the original image. Red is areas of decreased brightness and blue is areas of increased brightness."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHAAAABwBAMAAAA0zul4AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAD1BMVEX5+PmKEA0JLFi53vf///9lXu7+AAAAAWJLR0QEj2jZUQAAAAd0SU1FB+ICFgEfLRGtc9YAAAA1SURBVFjD7dIhAQAgDADBVViFVVj/bngECsO48+8+AgA4yJwfAnBT1fyQXffk8KE1PQ0Af1vqRARBLlY/vgAAAABJRU5ErkJggg==",
      "text/plain": [
       "28×28 Array{RGB{Float64},2}:\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)  …  RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)  …  RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)  …  RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " ⋮                                         ⋱                                          \n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.723685,0.871963,0.968818)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)  …  RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)  …  RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.974598,0.972607,0.975359)"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "diff = getvalue(d[:Perturbation])\n",
    "view_diff(diff[1, :, :, 1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "### $l_\\infty$\n",
    "\n",
    "We can also minimize over the $l_\\infty$ norm. This generally results in large patches of the image being changed. \n",
    "\n",
    "In this case, the minimum $l_\\infty$ norm perturbation required for the image to be classified as a `9` is `0.033522.`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [10]\n",
      "\u001b[39mObjective Value: 0.033522, Solve Time: 3.30\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHAAAABwCAAAAADji6uXAAAABGdBTUEAALGPC/xhBQAAAAJiS0dEAP+Hj8y/AAAAB3RJTUUH4gIWAR8xBawvmQAAAmNJREFUaN7tmD1rFUEUhrewuaAp/QEpFRIIWoR0FnZa2gSbpIrYWQghJKL4C0wrWpk/kFqbfBAIFoKFWCmYLxTjFwEL43Pgjsw998zuXDJjdZ5mv2bOM8u+O3f2Nr0EDfQyaCJy+jZthVxYVBh3bAy0ULdP1nJhNWHqQVvFtVgPrHXwLqwm7BJpYe4AdE0X1hd2dTprgFxYR6gDMkoRq32qpgvrCVNFU53a6KzjwmpCq4PueAcW4BaswHXQfVNhc2E9YXwwD0/gI/yEeCt8h1P4CrL9A3J9G86DHmRyonBhUWHYeQSnfX5B2Ib9+NhiC8agTebCusJ3IEVl+1LxEK4Y3Ie3EKTrEMLTmVAXFhdOwiycA+vlTXEZdiFIl8CasIdC48LiwviC9cIOPfyozW0Ik8MPSPU3U+TCMwtTD7dNprex8APoWnrfhWWFXQJLGBe4By8gCI/gEsQDcmF9Ye4LPw534T186SMLYb3A2od4gh8YsAurCdtkN+ABfIKchfFj0Dfw76ZcWEWYCswEbIAWHMBmn2swA68htFmGRjEQGhcWFcYn4guL8AakyCF8BvljaA4ugi74CqTtb5iCVABdWF8YeA4SgDW4ClabwDQcQ1gIWy/9UH8XFhO2XZQFkhUoLYwXwk/BGtTATOPC4kIrSamA6PNyvAoSsBOQydx62V1YX2hJc9iBbyCBeQaWzIX/V6gbdiE/zhKYPQiB0aEacLiwunAUZEEVFk7ywWMNfOhGXFhVaAWn7Zx8zMgfCzJ59zJxYX1hsqEKwgWQD8+bMEoNF5YXBnI75Q4odc2FxYV/AV+uSOnU7chPAAAAAElFTkSuQmCC",
      "text/plain": [
       "28×28 Array{Gray{Float64},2}:\n",
       " Gray{Float64}(0.0335223)  …  Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0)      \n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)  …  Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0)           Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)  …  Gray{Float64}(0.0)      \n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0)      \n",
       " ⋮                         ⋱                          \n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0)           Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0)           Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)  …  Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)  …  Gray{Float64}(0.0335223)\n",
       " Gray{Float64}(0.0335223)     Gray{Float64}(0.0)      \n",
       " Gray{Float64}(0.0)           Gray{Float64}(0.0335223)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d = MIPVerify.find_adversarial_example(n1params, sample_image, 10, GurobiSolver(OutputFlag=0),\n",
    "    norm_order=Inf);\n",
    "print_summary(d)\n",
    "perturbed_sample_image = getvalue(d[:PerturbedInput])\n",
    "colorview(Gray, perturbed_sample_image[1, :, :, 1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHAAAABwBAMAAAA0zul4AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAGFBMVEXr9/35+Pn/8e3v+f7x+v7w+f7/8+////+Hc45DAAAAAWJLR0QHFmGI6wAAAAd0SU1FB+ICFgEfMQWsL5kAAAFKSURBVFjD1ZfRDcMwCES9glfwCl7BK2SF7D9C5RLKgXEi9St3UuXW5hEJA6GlgGoti+pXu1M+UA7rTwrq/s0DXg+iBzNXWJ0lQSQCI2TXvjpIURJwveanEDGB/sqjiU943WED0XQ5CsEL4SMCfQLctWVO0Mxa089U762NoSdY1PAkElAOeh9jGk5kDFlNgi4YGTjD0B6E4LUSgXr9NZE6NPMlQCRgUtlQ0jMlshGDBdwNsdiaJO1DcIjAnbBotbT3DfvtYHb5ktqyWusK7YoKzOKUN+aQOzRgDM1xCIAtWpM8iSsB6Ac7NfEvUxsjQISgGGgy+z8rs5QtiNceEYg/DdIdMZJ09664QEwCPDQjaVtJSRCBPg28rIzRkhPEK4+gjoABogNzldK7JkAyyFOB+Mq0b+dpodmKCFyd/GHxUjBJ3AdHt3PVG8EPiuAasNBMBxIAAAAASUVORK5CYII=",
      "text/plain": [
       "28×28 Array{RGB{Float64},2}:\n",
       " RGB{Float64}(0.92128,0.968212,0.993551)   …  RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)   …  RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)   …  RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " ⋮                                         ⋱                                          \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)   …  RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)   …  RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.92128,0.968212,0.993551) "
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "diff = getvalue(d[:Perturbation])\n",
    "view_diff(diff[1, :, :, 1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "### $l_2$\n",
    "With solvers that can handle MIQPs (like Gurobi), we can minimize over the $l_2$ norm. This generally takes a bit more time. \n",
    "\n",
    "In this case, the minimum $l_2$ norm perturbation required for the image to be classified as a `9` is `0.183 = sqrt(0.033522).`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [10]\n",
      "\u001b[39mObjective Value: 0.328904, Solve Time: 23.61\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHAAAABwCAAAAADji6uXAAAABGdBTUEAALGPC/xhBQAAAAJiS0dEAP+Hj8y/AAAAB3RJTUUH4gIWASAMBRpJtAAAA/tJREFUaN7tmsurTlEYxr9zc7+GKGWKMnIbyEBGSpmICSOZGSgxQZnJhLmJwTHyNyAyUpSBZESKotwpl+NyPL/dfnavZX85g3Vm72/wrbXXXut91td+1+3dezAixgXpQEyIUUGedE7LmJgrKFvQQtkgQD1skR9poY7Txm4KVhccbaHQKYbdgdKooS6di2Kk84QFXS/+mRSsLzjeQgFCNKQRN90Y0Wg80tcxOxh2sbFQ2H4Kzo4gxriwiCuQxkkgCrmTJW67WNhR/Ae6hilYVZCMJ107iVM3spg7MEzM9ZYKl3kS8QSegvUFPWCpvEiURpYI0vnCZR7sfWDPHWKRdud9LwXrC8YNVLxpB+Chx4mZuhMFdqQ+Z/KfwE7T6RScFUFvdOLGp3QO8kfFEbFPnBW7BYLdJjdQ2kB4mUjB+oK+ScPD4pK4L96Kl+KdeNXyXfwQX8W0IH0jbokVouxkFEfQm+UUrCvoA+YFgTEMfRKkU4Ky34Jr8t8EQr9afgrqIbpalGI4FAO+O/ykYHVBflhknwmMPhJ3xE1xW5A/L7aKbWKz2C52inPiiXBHrgs7j8G+J5euIAWrCjrAs1EcFJTFDdP/WC8eCpwH5zolvGAz0H2I8aEpBesLeuPqDZBTHrIbug4TczfjB4ego9Mtr0X0DfK088EoBesLgoM4vsk1DZx6A9QEdkKnbPCAsCALtQc592nvzjngkIJ1BeMCSeoHDAQHmIzJ+56fux3omLgiLPhZbBF2PNdngehOwClYVTBOrqRrBSI8bEQQ8wLKvePiuXjRwqSNEBsqb5TZRMcJfrnwC5MUrC8YF1sGJkI4A3nuMdj3CA6gT8UXYQfxZhiRqRbyHIj8B+JBtHGiFKwuGBdUB8PHWjaIG8ICOAiOgbPca9krdgk20K7DRmpQwMBfJVKwvqCJEwBiJ8VjgZEPgsF+QhB4WCdKg3eFAw2bBJ1nwK8R2MN5HOxNwdkRjM4DkwIHuSZ2CMqGvYDmkEqACMH3InY+Ltp/aaRgNUFPsvGjD+ABnxbkY+C2DMRC3AhfFX2dwmm6l84pWF0wfhTQF2CP9JVfFCzEBIdwMC/esXPdC8sUrC5Ihom2DBYMZsgDwQRhh8EotkpBHKZ5mZaC1QUdAPLETMVhHwb08VH4AEPQtnQqOwsb7KYDKVhdkAIEygV4JhwSDrDvF/EFNTb9URfXCDadScHqgsBAtzDXPFx/hOPgXPxwxwFbXmzyYuyyIPjgOisFCzg2HCxk0HebsBSsKshD9eD3IPXLRQduHXjwJG8nOyMIOPiDEAcKnffHzF1QCFKwuqDxwQP88Knoj3TYGPmFSgw82Cg2qIPz2EY3YQ/+PdikYDXBP9MD/hoaqXvGAAAAAElFTkSuQmCC",
      "text/plain": [
       "28×28 Array{Gray{Float64},2}:\n",
       " Gray{Float64}(0.00293786)   …  Gray{Float64}(0.00695505)\n",
       " Gray{Float64}(0.00746987)      Gray{Float64}(0.0207089) \n",
       " Gray{Float64}(0.0152496)       Gray{Float64}(0.0286317) \n",
       " Gray{Float64}(0.0144787)       Gray{Float64}(0.0)       \n",
       " Gray{Float64}(0.0208144)       Gray{Float64}(0.0128456) \n",
       " Gray{Float64}(0.0104285)    …  Gray{Float64}(0.0116598) \n",
       " Gray{Float64}(0.015601)        Gray{Float64}(0.0334463) \n",
       " Gray{Float64}(0.0162783)       Gray{Float64}(0.0632378) \n",
       " Gray{Float64}(0.0)             Gray{Float64}(0.0242176) \n",
       " Gray{Float64}(0.00729577)      Gray{Float64}(0.017876)  \n",
       " Gray{Float64}(0.0207985)    …  Gray{Float64}(0.0)       \n",
       " Gray{Float64}(0.0390298)       Gray{Float64}(0.0178851) \n",
       " Gray{Float64}(0.0127734)       Gray{Float64}(0.0)       \n",
       " ⋮                           ⋱                           \n",
       " Gray{Float64}(0.0342939)       Gray{Float64}(0.0063349) \n",
       " Gray{Float64}(0.0238592)       Gray{Float64}(0.0809298) \n",
       " Gray{Float64}(0.0)             Gray{Float64}(0.0533926) \n",
       " Gray{Float64}(0.0)             Gray{Float64}(0.0220741) \n",
       " Gray{Float64}(0.0151549)    …  Gray{Float64}(0.0257883) \n",
       " Gray{Float64}(0.0155936)       Gray{Float64}(0.01081)   \n",
       " Gray{Float64}(0.00305089)      Gray{Float64}(0.0303155) \n",
       " Gray{Float64}(0.00917047)      Gray{Float64}(0.00668497)\n",
       " Gray{Float64}(0.00371888)      Gray{Float64}(0.0052561) \n",
       " Gray{Float64}(0.000449911)  …  Gray{Float64}(0.0132231) \n",
       " Gray{Float64}(0.025078)        Gray{Float64}(0.0)       \n",
       " Gray{Float64}(0.0)             Gray{Float64}(0.0027629) "
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d = MIPVerify.find_adversarial_example(n1params, sample_image, 10, GurobiSolver(OutputFlag=0),\n",
    "    norm_order=2);\n",
    "print_summary(d)\n",
    "perturbed_sample_image = getvalue(d[:PerturbedInput])\n",
    "colorview(Gray, perturbed_sample_image[1, :, :, 1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHAAAABwCAMAAADxPgR5AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAdVBMVEXy+v7v+f7x+v7u+P7w+f75+Pnx+f7t+P7s9/3q9/3r9/3p9v3n9f3l9P3o9v3m9f3k9P3/4tr/9PH/9fH/9fL/9fPq9v3/9PD/7+r/8u7/8+//8Ov/8/D/8e3/9vP/8u//7uni8/zb8Pzg8vze8fzh8/z///9qy2chAAAAAWJLR0QmWgiYtQAAAAd0SU1FB+ICFgEgDAUaSbQAAANpSURBVGje7ZrZUttAEEUNsYHsJED2QBKS///F9HHNcd2oBOFh/Nb3wSPNdtqlnp5F2mxKJ6XTEtfPStvSrnRWOh8i76JE3vMh2u1C1DPvdIh2prTdNHA6cDuUhTQkpaHwpcjHuISRYpTG8gfskzzqN3A+8GTIyjR8UTIln/LsPEXH1kljdCD6fFmy/wYeB3geAmIFUp1m6TzLQa9s+6qko9CnBjdwPpALQBaQaWojYRrwPwd6XTLPgG8QaOB8YDrFm9Kyk7elNGL/4EuZptIgJmmDuWUNnA90AeUDXjqAC6jMT0dz0ZWTQMo/YVBp4HGALnR0AmEa4nUuuARq0DK4L/sAfFlq4HxgDlYqYcC7EnnvS9xflbi+LlH/pqQBGEk7y9aCAeUAMa6B84E0+lD6WPIhfyqRkgfIjrj+PHQzBIj8xzY9BHH/VAPnA/lhksUxgHD/pfS1RMffStx/H8IYUkAAb0sA70rXQwmkP4PL3vAGTgfiMGaQ/ijxkHdPFB1iLCDgDHI7N8Bz7aa2gfOBywWQFbKhdZx41xyCwOCBHmV5+EeeG6MGzgcuHy4NuWfzycIYp2LyZJPpQtmOloexCOdJQ2mvcfTZwPlAMtlkmPqAEUH9Z4lrylzcCsGws6F0GAKAQOvTFwY2cD4wgyvprxIQHjYQYJQZCJiUc5J1UUwek/XVUAZ4NjGHDVMDpwPzwIeBCciB72G7kyeNWEDpILdDbnaQMP+AQcMJoYHzgTmhehi+DeVLMB2DOgIAkkeZdXYrYuDflxo4H2hGBgBhbEjthImZQU7+WqeADehOBAz43yX6xHkIIg08HjCdBxGk3Yh64PDYwQEGu6FN43PSPpxENXAqMDcxWehg5joPbteguRD2IGmpw+FeA48CzBeQawfsqTQqnYaBzyaUdk7eblQ1en/fwOlAKrhYsoOHXiqvCSdxMUyg8EMED2WtdzHUwPlAJ1sDAPCHPuxYEzAP91xsZbmLMBbY/3xI18BpQDJ80E+FKJ0CZ8B58gU1judHXdw38HhAC/2YlXsK/OjDA3cXSl77UgQQiywWuTrfnxLt2YjSL2CdsYHzgR7QOVmS5sfIQPLjLA8ZqOe1C2CurWO5RhgQGjgf6CA2U7idujlhYeQLlXxBIpQ+qLPfdA7DcxLWMRs4HfgXZsJqEDr2AoQAAAAASUVORK5CYII=",
      "text/plain": [
       "28×28 Array{RGB{Float64},2}:\n",
       " RGB{Float64}(0.947578,0.979616,0.996444)  …  RGB{Float64}(0.944334,0.978226,0.996088)\n",
       " RGB{Float64}(0.942708,0.977527,0.99591)      RGB{Float64}(0.932883,0.973281,0.99483) \n",
       " RGB{Float64}(0.93617,0.974706,0.995192)      RGB{Float64}(0.926271,0.970399,0.994102)\n",
       " RGB{Float64}(0.937809,0.975415,0.995372)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.932883,0.973281,0.99483)      RGB{Float64}(0.939445,0.976121,0.995552)\n",
       " RGB{Float64}(0.941078,0.976825,0.995731)  …  RGB{Float64}(0.939445,0.976121,0.995552)\n",
       " RGB{Float64}(0.93617,0.974706,0.995192)      RGB{Float64}(0.92128,0.968212,0.993551) \n",
       " RGB{Float64}(0.93617,0.974706,0.995192)      RGB{Float64}(0.895906,0.95692,0.990729) \n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.929583,0.971845,0.994467)\n",
       " RGB{Float64}(0.942708,0.977527,0.99591)      RGB{Float64}(0.934528,0.973994,0.995011)\n",
       " RGB{Float64}(0.932883,0.973281,0.99483)   …  RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.916261,0.966001,0.992996)     RGB{Float64}(0.934528,0.973994,0.995011)\n",
       " RGB{Float64}(0.939445,0.976121,0.995552)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " ⋮                                         ⋱                                          \n",
       " RGB{Float64}(0.92128,0.968212,0.993551)      RGB{Float64}(0.944334,0.978226,0.996088)\n",
       " RGB{Float64}(0.929583,0.971845,0.994467)     RGB{Float64}(0.88035,0.949853,0.988974) \n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.904441,0.96075,0.991684) \n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.931235,0.972564,0.994649)\n",
       " RGB{Float64}(0.93617,0.974706,0.995192)   …  RGB{Float64}(0.927929,0.971123,0.994285)\n",
       " RGB{Float64}(0.93617,0.974706,0.995192)      RGB{Float64}(0.941078,0.976825,0.995731)\n",
       " RGB{Float64}(0.945958,0.978922,0.996267)     RGB{Float64}(0.924611,0.969673,0.993919)\n",
       " RGB{Float64}(0.941078,0.976825,0.995731)     RGB{Float64}(0.944334,0.978226,0.996088)\n",
       " RGB{Float64}(0.945958,0.978922,0.996267)     RGB{Float64}(0.944334,0.978226,0.996088)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)  …  RGB{Float64}(0.937809,0.975415,0.995372)\n",
       " RGB{Float64}(0.927929,0.971123,0.994285)     RGB{Float64}(0.974598,0.972607,0.975359)\n",
       " RGB{Float64}(0.974598,0.972607,0.975359)     RGB{Float64}(0.947578,0.979616,0.996444)"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "diff = getvalue(d[:Perturbation])\n",
    "view_diff(diff[1, :, :, 1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# Advanced Options"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Models\n",
    "Finding adversarial examples consists of two steps:\n",
    "\n",
    "  1. Building a model that expresses the input-output constraints of the neural net, which involves determining upper and lower bounds on each intermediate value.\n",
    "  2. Setting a target category (or multiple target categories) and solving to determine the minimal adversarial example that is classified in that category.\n",
    "\n",
    "The first time we verify a neural net, we must do step 1, which can take a long time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Rebuilding model from scratch. This may take some time as we determine upper and lower bounds for the input to each non-linear unit. The model built will be cached and re-used for future solves, unless you explicitly set rebuild=false.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [1]\n",
      "\u001b[39m207.519314 seconds (610.00 k allocations: 98.722 MiB, 0.01% gc time)\n",
      "Objective Value: 15.092612, Solve Time: 37.63\n"
     ]
    }
   ],
   "source": [
    "d = @time MIPVerify.find_adversarial_example(n1params, sample_image, 1, GurobiSolver(OutputFlag=0), rebuild=true);\n",
    "print_summary(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "When re-running the solve (with the `rebuild` parameter defaulting to `false`), we load the model from cache and skip ahead straight to step 2; finding the adversarial example takes much less time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [1]\n",
      "\u001b[39m 37.035422 seconds (503.36 k allocations: 22.175 MiB, 0.06% gc time)\n",
      "Objective Value: 15.092612, Solve Time: 36.95\n"
     ]
    }
   ],
   "source": [
    "d = @time MIPVerify.find_adversarial_example(n1params, sample_image, 1, GurobiSolver(OutputFlag=0));\n",
    "print_summary(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "By setting `rebuild=true`, you force the MIP model to be rebuilt even if one exists; this is potentially useful if you want to spend more time expressing the neural net as an MIP model to speed up subsequent solves. (Think of this as an investment!)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "### Removing Cached Models\n",
    "\n",
    "If you find that your cached models are taking up too much space, you can remove them with `remove_cached_models()`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Advanced Solver-fu\n",
    "\n",
    "We use two different solvers for the two steps of finding adversarial examples:\n",
    "\n",
    "  1. the `model_build_solver`, used only to determine upper and lower bounds on intermediate values when expressing the input-output constraints in the neural net (i.e. if no cached model exists, or if `rebuild=true`), and \n",
    "  2. the `main_solver`, used to determine the minimal adversarial example for the loaded model.\n",
    "  \n",
    "We will be focusing on the parameters available via Gurobi (http://www.gurobi.com/documentation/7.5/refman/parameters.html), but other solvers often have similar options."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "  \n",
    "### `main_solver`\n",
    "\n",
    "#### Muting Output\n",
    "To mute the output from the `GurobiSolver`, set `OutputFlag=0`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [10]\n",
      "\u001b[39mOptimize a model with 3385 rows, 3256 columns and 71132 nonzeros\n",
      "Variable types: 3196 continuous, 60 integer (60 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [2e-05, 7e+02]\n",
      "  Objective range  [1e+00, 1e+00]\n",
      "  Bounds range     [1e+00, 1e+02]\n",
      "  RHS range        [1e-02, 7e+02]\n",
      "Presolve removed 2860 rows and 2184 columns\n",
      "Presolve time: 0.13s\n",
      "Presolved: 525 rows, 1072 columns, 65472 nonzeros\n",
      "\n",
      "MIP start did not produce a new incumbent solution\n",
      "MIP start violates constraint R1024 by 1.000000000\n",
      "\n",
      "Variable types: 1012 continuous, 60 integer (60 binary)\n",
      "\n",
      "Root relaxation: objective 0.000000e+00, 249 iterations, 0.01 seconds\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "     0     0    0.00000    0    7          -    0.00000      -     -    0s\n",
      "Another try with MIP start\n",
      "H    0     0                      42.6307071    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    7   42.63071    0.00000   100%     -    0s\n",
      "H    0     0                      17.9461784    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    6   17.94618    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    6   17.94618    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    8   17.94618    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    1   17.94618    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    1   17.94618    0.00000   100%     -    0s\n",
      "H    0     0                       3.1718557    0.00000   100%     -    0s\n",
      "     0     2    0.00000    0    1    3.17186    0.00000   100%     -    0s\n",
      "\n",
      "Cutting planes:\n",
      "  Gomory: 1\n",
      "  MIR: 6\n",
      "  Flow cover: 3\n",
      "\n",
      "Explored 2129 nodes (154479 simplex iterations) in 3.47 seconds\n",
      "Thread count was 8 (of 8 available processors)\n",
      "\n",
      "Solution count 3: 3.17186 17.9462 42.6307 \n",
      "Pool objective bound 3.17186\n",
      "\n",
      "Optimal solution found (tolerance 1.00e-04)\n",
      "Best objective 3.171855696756e+00, best bound 3.171855696756e+00, gap 0.0000%\n",
      "Objective Value: 3.171856, Solve Time: 3.47\n"
     ]
    }
   ],
   "source": [
    "d = MIPVerify.find_adversarial_example(n1params, sample_image, 10, GurobiSolver());\n",
    "print_summary(d)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [10]\n",
      "\u001b[39mObjective Value: 3.171856, Solve Time: 3.47\n"
     ]
    }
   ],
   "source": [
    "MIPVerify.find_adversarial_example(n1params, sample_image, 10, GurobiSolver(OutputFlag=0));\n",
    "print_summary(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "#### Terminating early if a conditon is satisfied\n",
    "\n",
    "Sometimes, finding an adversarial example takes a long time:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [2]\n",
      "\u001b[39mOptimize a model with 4954 rows, 4041 columns and 75836 nonzeros\n",
      "Variable types: 3197 continuous, 844 integer (844 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [2e-05, 7e+02]\n",
      "  Objective range  [1e+00, 1e+00]\n",
      "  Bounds range     [1e+00, 1e+02]\n",
      "  RHS range        [1e-02, 7e+02]\n",
      "Presolve removed 3813 rows and 3136 columns\n",
      "Presolve time: 0.12s\n",
      "Presolved: 1141 rows, 905 columns, 66704 nonzeros\n",
      "\n",
      "MIP start did not produce a new incumbent solution\n",
      "MIP start violates constraint R1024 by 1.000000000\n",
      "\n",
      "Variable types: 845 continuous, 60 integer (60 binary)\n",
      "\n",
      "Root relaxation: objective 0.000000e+00, 546 iterations, 0.02 seconds\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "     0     0    0.00000    0    5          -    0.00000      -     -    0s\n",
      "Another try with MIP start\n",
      "H    0     0                       0.4206663    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0   10    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0   11    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    1    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    1    0.42067    0.00000   100%     -    1s\n",
      "     0     2    0.00000    0    1    0.42067    0.00000   100%     -    1s\n",
      "   252   237 infeasible   33         0.42067    0.00000   100%   305    5s\n",
      "H 1116   587                       0.3080739    0.00000   100%   165   10s\n",
      "H 1119   555                       0.2873450    0.00000   100%   165   11s\n",
      "H 1327   598                       0.2311859    0.00000   100%   169   13s\n",
      "H 1386   555                       0.2026951    0.00000   100%   166   14s\n",
      "* 1441   528              48       0.1992454    0.00000   100%   163   14s\n",
      "* 1442   504              48       0.1991103    0.00000   100%   162   14s\n",
      "  1563   515    0.19625   42    9    0.19911    0.00000   100%   160   15s\n",
      "  2313   429    0.11042   30    9    0.19911    0.00000   100%   180   20s\n",
      "  3061   445    0.08632   27   14    0.19911    0.01024  94.9%   191   25s\n",
      "  3707   649    0.18139   37    9    0.19911    0.02481  87.5%   187   30s\n",
      "  4196   701    0.16025   28   13    0.19911    0.02481  87.5%   191   35s\n",
      "  4693   736    0.14166   31   12    0.19911    0.04052  79.6%   191   40s\n",
      "  5514   858    0.15499   27   14    0.19911    0.04984  75.0%   185   45s\n",
      "* 5760   842              43       0.1933421    0.04984  74.2%   184   46s\n",
      "  6375   808    0.17122   32    9    0.19334    0.06626  65.7%   181   50s\n",
      "* 6391   767              48       0.1879605    0.06626  64.7%   181   50s\n",
      "  7136   840    0.12610   23   16    0.18796    0.08395  55.3%   176   55s\n",
      "  8183   841    0.09461   24   17    0.18796    0.09461  49.7%   167   60s\n",
      "  9955   878    0.10454   20   17    0.18796    0.10454  44.4%   156   66s\n",
      " 10963   852    0.13438   31   10    0.18796    0.13438  28.5%   149   70s\n",
      "*11225   851              43       0.1852948    0.13587  26.7%   147   70s\n",
      " 12515   779    0.14723   21   18    0.18529    0.14723  20.5%   140   76s\n",
      " 13973   602    0.16486   29    9    0.18529    0.15895  14.2%   134   80s\n",
      " 14536   542 infeasible   29         0.18529    0.16608  10.4%   132   87s\n",
      "H14540   542                       0.1852948    0.16609  10.4%   132   87s\n",
      " 15393   262    0.17325   19   16    0.18529    0.17325  6.50%   129   90s\n",
      "\n",
      "Cutting planes:\n",
      "  Gomory: 2\n",
      "  Projected Implied bound: 1\n",
      "  MIR: 2\n",
      "  Inf proof: 4\n",
      "\n",
      "Explored 16515 nodes (2033267 simplex iterations) in 92.52 seconds\n",
      "Thread count was 8 (of 8 available processors)\n",
      "\n",
      "Solution count 10: 0.185295 0.185295 0.187961 ... 0.308074\n",
      "Pool objective bound 0.185295\n",
      "\n",
      "Optimal solution found (tolerance 1.00e-04)\n",
      "Best objective 1.852948296314e-01, best bound 1.852948296314e-01, gap 0.0000%\n"
     ]
    }
   ],
   "source": [
    "MIPVerify.find_adversarial_example(n1params, sample_image, 2, GurobiSolver(),\n",
    "    norm_order=Inf);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "You may want to terminate early when a particular condition is satisfied. Common reasons are:\n",
    "\n",
    "  1. Solve exceeding time limit\n",
    "  2. Lower bound on robustness proved (i.e. `BestBd` increases above a pre-determined threshold)\n",
    "  3. Counter-example found (i.e. `Incumbent` adversarial image found that is closer to the original image than expected).\n",
    "  4. Difference between `Incumbent` and `BestBd` falls below a pre-determined threshold.\n",
    "  \n",
    "Fortunately, Gurobi has a parameter for all of these cases."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "##### Terminate if time limit is reached\n",
    "Set `TimeLimit`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [2]\n",
      "\u001b[39mOptimize a model with 4954 rows, 4041 columns and 75836 nonzeros\n",
      "Variable types: 3197 continuous, 844 integer (844 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [2e-05, 7e+02]\n",
      "  Objective range  [1e+00, 1e+00]\n",
      "  Bounds range     [1e+00, 1e+02]\n",
      "  RHS range        [1e-02, 7e+02]\n",
      "Presolve removed 3813 rows and 3136 columns\n",
      "Presolve time: 0.13s\n",
      "Presolved: 1141 rows, 905 columns, 66704 nonzeros\n",
      "\n",
      "MIP start did not produce a new incumbent solution\n",
      "MIP start violates constraint R1024 by 1.000000000\n",
      "\n",
      "Variable types: 845 continuous, 60 integer (60 binary)\n",
      "\n",
      "Root relaxation: objective 0.000000e+00, 546 iterations, 0.02 seconds\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "     0     0    0.00000    0    5          -    0.00000      -     -    0s\n",
      "Another try with MIP start\n",
      "H    0     0                       0.4206663    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0   10    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0   11    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    1    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    1    0.42067    0.00000   100%     -    1s\n",
      "     0     2    0.00000    0    1    0.42067    0.00000   100%     -    1s\n",
      "   328   285    0.21063   22   14    0.42067    0.00000   100%   260    5s\n",
      "H 1116   587                       0.3080739    0.00000   100%   165    9s\n",
      "  1117   584    0.18446    8    1    0.30807    0.00000   100%   165   10s\n",
      "H 1119   555                       0.2873450    0.00000   100%   165   10s\n",
      "H 1327   598                       0.2311859    0.00000   100%   169   13s\n",
      "H 1386   555                       0.2026951    0.00000   100%   166   13s\n",
      "* 1441   528              48       0.1992454    0.00000   100%   163   14s\n",
      "* 1442   504              48       0.1991103    0.00000   100%   162   14s\n",
      "  1658   514    0.15434   44    7    0.19911    0.00000   100%   157   15s\n",
      "  2369   427    0.18868   27   16    0.19911    0.00000   100%   182   20s\n",
      "  2859   445 infeasible   26         0.19911    0.00000   100%   190   25s\n",
      "  3342   506    0.02481   18   14    0.19911    0.02481  87.5%   191   30s\n",
      "\n",
      "Cutting planes:\n",
      "  Gomory: 2\n",
      "  Projected Implied bound: 1\n",
      "  MIR: 2\n",
      "  Inf proof: 1\n",
      "\n",
      "Explored 3353 nodes (648603 simplex iterations) in 30.00 seconds\n",
      "Thread count was 8 (of 8 available processors)\n",
      "\n",
      "Solution count 7: 0.19911 0.199245 0.202695 ... 0.420666\n",
      "Pool objective bound 0.0248115\n",
      "\n",
      "Time limit reached\n",
      "Best objective 1.991103454101e-01, best bound 2.481147579202e-02, gap 87.5388%\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[1m\u001b[33mWARNING: \u001b[39m\u001b[22m\u001b[33mNot solved to optimality, status: UserLimit\u001b[39m\n"
     ]
    }
   ],
   "source": [
    "MIPVerify.find_adversarial_example(n1params, sample_image, 2, GurobiSolver(TimeLimit=30),\n",
    "    norm_order=Inf);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "##### Terminate if lower bound on robustness proved\n",
    "\n",
    "Set `BestBdStop` or `Cutoff`.\n",
    "\n",
    "(`Cutoff` gives a different error message that is not currently processed correctly by the latest release of `Gurobi`)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [2]\n",
      "\u001b[39mOptimize a model with 4954 rows, 4041 columns and 75836 nonzeros\n",
      "Variable types: 3197 continuous, 844 integer (844 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [2e-05, 7e+02]\n",
      "  Objective range  [1e+00, 1e+00]\n",
      "  Bounds range     [1e+00, 1e+02]\n",
      "  RHS range        [1e-02, 7e+02]\n",
      "Presolve removed 3813 rows and 3136 columns\n",
      "Presolve time: 0.12s\n",
      "Presolved: 1141 rows, 905 columns, 66704 nonzeros\n",
      "\n",
      "MIP start did not produce a new incumbent solution\n",
      "MIP start violates constraint R1024 by 1.000000000\n",
      "\n",
      "Variable types: 845 continuous, 60 integer (60 binary)\n",
      "\n",
      "Root relaxation: objective 0.000000e+00, 546 iterations, 0.04 seconds\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "     0     0    0.00000    0    5          -    0.00000      -     -    0s\n",
      "Another try with MIP start\n",
      "H    0     0                       0.4206663    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0   10    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0   11    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    1    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    1    0.42067    0.00000   100%     -    1s\n",
      "     0     2    0.00000    0    1    0.42067    0.00000   100%     -    1s\n",
      "   159   155    0.07336   23   11    0.42067    0.00000   100%   355    5s\n",
      "   686   504    0.29531   29    8    0.42067    0.00000   100%   199   10s\n",
      "H 1116   587                       0.3080739    0.00000   100%   165   13s\n",
      "H 1119   555                       0.2873450    0.00000   100%   165   14s\n",
      "  1124   559    0.01313   27    3    0.28734    0.00000   100%   164   15s\n",
      "H 1327   598                       0.2311859    0.00000   100%   169   18s\n",
      "H 1386   555                       0.2026951    0.00000   100%   166   19s\n",
      "* 1441   528              48       0.1992454    0.00000   100%   163   19s\n",
      "* 1442   504              48       0.1991103    0.00000   100%   162   19s\n",
      "  1518   514    0.05300   40   10    0.19911    0.00000   100%   159   20s\n",
      "  1966   496 infeasible   35         0.19911    0.00000   100%   164   25s\n",
      "  2313   429    0.11042   30    9    0.19911    0.00000   100%   180   30s\n",
      "  2800   433    0.02953   27   12    0.19911    0.00000   100%   190   35s\n",
      "  3196   465     cutoff   30         0.19911    0.02127  89.3%   192   40s\n",
      "  3575   598    0.07928   25   14    0.19911    0.02481  87.5%   188   45s\n",
      "  3895   647    0.17212   25   14    0.19911    0.02481  87.5%   190   50s\n",
      "  4296   719    0.03363   26   13    0.19911    0.02545  87.2%   192   56s\n",
      "  4693   736    0.14166   31   12    0.19911    0.04052  79.6%   191   60s\n",
      "  5316   844 infeasible   39         0.19911    0.04984  75.0%   186   66s\n",
      "* 5760   842              43       0.1933421    0.04984  74.2%   184   69s\n",
      "\n",
      "Cutting planes:\n",
      "  Gomory: 2\n",
      "  Projected Implied bound: 1\n",
      "  MIR: 2\n",
      "  Inf proof: 3\n",
      "\n",
      "Explored 5916 nodes (1096359 simplex iterations) in 69.78 seconds\n",
      "Thread count was 8 (of 8 available processors)\n",
      "\n",
      "Solution count 8: 0.193342 0.19911 0.199245 ... 0.420666\n",
      "Pool objective bound 0.0568032\n",
      "\n",
      "Optimization achieved user objective limit\n",
      "Best objective 1.933420946116e-01, best bound 5.680322870831e-02, gap 70.6204%\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[1m\u001b[33mWARNING: \u001b[39m\u001b[22m\u001b[33mNot solved to optimality, status: UserObjLimit\u001b[39m\n"
     ]
    }
   ],
   "source": [
    "MIPVerify.find_adversarial_example(n1params, sample_image, 2, GurobiSolver(BestBdStop=0.05),\n",
    "    norm_order=Inf);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "##### Terminate if adversarial example found closer than expected robustness\n",
    "\n",
    "Set `BestObjStop`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [2]\n",
      "\u001b[39mOptimize a model with 4954 rows, 4041 columns and 75836 nonzeros\n",
      "Variable types: 3197 continuous, 844 integer (844 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [2e-05, 7e+02]\n",
      "  Objective range  [1e+00, 1e+00]\n",
      "  Bounds range     [1e+00, 1e+02]\n",
      "  RHS range        [1e-02, 7e+02]\n",
      "Presolve removed 3813 rows and 3136 columns\n",
      "Presolve time: 0.15s\n",
      "Presolved: 1141 rows, 905 columns, 66704 nonzeros\n",
      "\n",
      "MIP start did not produce a new incumbent solution\n",
      "MIP start violates constraint R1024 by 1.000000000\n",
      "\n",
      "Variable types: 845 continuous, 60 integer (60 binary)\n",
      "\n",
      "Root relaxation: objective 0.000000e+00, 546 iterations, 0.03 seconds\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "     0     0    0.00000    0    5          -    0.00000      -     -    0s\n",
      "Another try with MIP start\n",
      "H    0     0                       0.4206663    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0   10    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0   11    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    1    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    1    0.42067    0.00000   100%     -    1s\n",
      "     0     2    0.00000    0    1    0.42067    0.00000   100%     -    2s\n",
      "    90    92    0.18868   14    9    0.42067    0.00000   100%   381    5s\n",
      "   524   427    0.37509   21   12    0.42067    0.00000   100%   219   10s\n",
      "H 1116   587                       0.3080739    0.00000   100%   165   15s\n",
      "H 1119   555                       0.2873450    0.00000   100%   165   16s\n",
      "  1290   649    0.00000   28   10    0.28734    0.00000   100%   172   20s\n",
      "H 1327   598                       0.2311859    0.00000   100%   169   20s\n",
      "H 1386   555                       0.2026951    0.00000   100%   166   20s\n",
      "* 1441   528              48       0.1992454    0.00000   100%   163   21s\n",
      "* 1442   504              48       0.1991103    0.00000   100%   162   21s\n",
      "\n",
      "Cutting planes:\n",
      "  Gomory: 2\n",
      "  Projected Implied bound: 1\n",
      "  MIR: 2\n",
      "\n",
      "Explored 1456 nodes (245195 simplex iterations) in 21.03 seconds\n",
      "Thread count was 8 (of 8 available processors)\n",
      "\n",
      "Solution count 7: 0.19911 0.199245 0.202695 ... 0.420666\n",
      "Pool objective bound 0\n",
      "\n",
      "Optimization achieved user objective limit\n",
      "Best objective 1.991103454101e-01, best bound 0.000000000000e+00, gap 100.0000%\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[1m\u001b[33mWARNING: \u001b[39m\u001b[22m\u001b[33mNot solved to optimality, status: UserObjLimit\u001b[39m\n"
     ]
    }
   ],
   "source": [
    "MIPVerify.find_adversarial_example(n1params, sample_image, 2, GurobiSolver(BestObjStop=0.2),\n",
    "    norm_order=Inf);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "##### Terminate if gap between `Incumbent` and `BestBd` is below threshold\n",
    "\n",
    "Set `MIPGap`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[36m[notice | MIPVerify]: Loading model from cache.\n",
      "\u001b[39m\u001b[36m[notice | MIPVerify]: Attempting to find adversarial example. Neural net predicted label is 8, target labels are [2]\n",
      "\u001b[39mOptimize a model with 4954 rows, 4041 columns and 75836 nonzeros\n",
      "Variable types: 3197 continuous, 844 integer (844 binary)\n",
      "Coefficient statistics:\n",
      "  Matrix range     [2e-05, 7e+02]\n",
      "  Objective range  [1e+00, 1e+00]\n",
      "  Bounds range     [1e+00, 1e+02]\n",
      "  RHS range        [1e-02, 7e+02]\n",
      "Presolve removed 3813 rows and 3136 columns\n",
      "Presolve time: 0.15s\n",
      "Presolved: 1141 rows, 905 columns, 66704 nonzeros\n",
      "\n",
      "MIP start did not produce a new incumbent solution\n",
      "MIP start violates constraint R1024 by 1.000000000\n",
      "\n",
      "Variable types: 845 continuous, 60 integer (60 binary)\n",
      "\n",
      "Root relaxation: objective 0.000000e+00, 546 iterations, 0.03 seconds\n",
      "\n",
      "    Nodes    |    Current Node    |     Objective Bounds      |     Work\n",
      " Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time\n",
      "\n",
      "     0     0    0.00000    0    5          -    0.00000      -     -    0s\n",
      "Another try with MIP start\n",
      "H    0     0                       0.4206663    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    0s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0   10    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    9    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    8    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0   11    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    1    0.42067    0.00000   100%     -    1s\n",
      "     0     0    0.00000    0    1    0.42067    0.00000   100%     -    1s\n",
      "     0     2    0.00000    0    1    0.42067    0.00000   100%     -    2s\n",
      "    90    92    0.18868   14    9    0.42067    0.00000   100%   381    5s\n",
      "   507   419    0.09126   19   14    0.42067    0.00000   100%   217   10s\n",
      "H 1116   587                       0.3080739    0.00000   100%   165   16s\n",
      "H 1119   555                       0.2873450    0.00000   100%   165   16s\n",
      "  1187   603    0.06626   20   11    0.28734    0.00000   100%   177   20s\n",
      "H 1327   598                       0.2311859    0.00000   100%   169   21s\n",
      "H 1386   555                       0.2026951    0.00000   100%   166   21s\n",
      "* 1441   528              48       0.1992454    0.00000   100%   163   22s\n",
      "* 1442   504              48       0.1991103    0.00000   100%   162   22s\n",
      "  1783   520     cutoff   32         0.19911    0.00000   100%   158   25s\n",
      "  2238   454     cutoff   28         0.19911    0.00000   100%   172   30s\n",
      "  2614   398    0.17469   36    9    0.19911    0.00000   100%   189   35s\n",
      "  3118   447    0.06092   31    9    0.19911    0.01651  91.7%   192   40s\n",
      "  3575   598    0.07928   25   14    0.19911    0.02481  87.5%   188   46s\n",
      "  3895   647    0.17212   25   14    0.19911    0.02481  87.5%   190   50s\n",
      "  4296   719    0.03363   26   13    0.19911    0.02545  87.2%   192   56s\n",
      "  4693   736    0.14166   31   12    0.19911    0.04052  79.6%   191   61s\n",
      "  5316   844 infeasible   39         0.19911    0.04984  75.0%   186   66s\n",
      "  5692   858    0.15558   19   14    0.19911    0.04984  75.0%   185   70s\n",
      "* 5760   842              43       0.1933421    0.04984  74.2%   184   70s\n",
      "  6375   808    0.17122   32    9    0.19334    0.06626  65.7%   181   76s\n",
      "* 6391   767              48       0.1879605    0.06626  64.7%   181   76s\n",
      "  6863   822    0.16684   27   13    0.18796    0.06626  64.7%   178   80s\n",
      "  7429   851    0.08395   25   13    0.18796    0.08395  55.3%   174   85s\n",
      "  8668   929    0.10390   28   14    0.18796    0.10390  44.7%   162   92s\n",
      "  9141   951    0.14661   26   13    0.18796    0.10454  44.4%   159   95s\n",
      "  9955   878    0.10454   20   17    0.18796    0.10454  44.4%   156  100s\n",
      "\n",
      "Cutting planes:\n",
      "  Gomory: 2\n",
      "  Projected Implied bound: 1\n",
      "  MIR: 2\n",
      "  Inf proof: 4\n",
      "\n",
      "Explored 10296 nodes (1589142 simplex iterations) in 100.25 seconds\n",
      "Thread count was 8 (of 8 available processors)\n",
      "\n",
      "Solution count 9: 0.187961 0.193342 0.19911 ... 0.420666\n",
      "Pool objective bound 0.118901\n",
      "\n",
      "Optimal solution found (tolerance 4.00e-01)\n",
      "Best objective 1.879605458797e-01, best bound 1.189014214184e-01, gap 36.7413%\n"
     ]
    }
   ],
   "source": [
    "MIPVerify.find_adversarial_example(n1params, sample_image, 2, GurobiSolver(MIPGap=0.4),\n",
    "    norm_order=Inf);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "### `model_build_solver`\n",
    "The default model build solver has the same type as the `main_solver`, but uses the default settings for that solver type other than 1) muting the output and 2) setting a time limit of 20s per solve (i.e. per upper/lower bound per intermediate value).\n",
    "\n",
    "The most common reason to pass in your own `model_build_solver` to modify the time limit per solve."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "Whew! That was a lot. The next tutorial will introduce you to everything you can extract from the results dictionary."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Julia 0.6.0",
   "language": "julia",
   "name": "julia-0.6"
  },
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "0.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
